/**
 * <p>Title: ConnectionPoolUtil.java</p>
 * <p>Description: JDBC连接池utils</p>
 * <p>Company: www.huoyunren.com</p>
 * @author duanxiangyun
 * @date 2015年1月7日
 * @version 1.0
 */
package com.duan.test.utils.common;

import java.io.PrintStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
//import java.sql.SQLException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;

/**
 * 连接池
 */
public class ConnectionPoolUtil {
	private static LinkedList<ConnectionWrapperUtil> m_notUsedConnection = new LinkedList<ConnectionWrapperUtil>();
	private static HashSet<ConnectionWrapperUtil> m_usedUsedConnection = new HashSet<ConnectionWrapperUtil>();
	private static String m_url = "";
	private static String m_user = "";
	private static String m_password = "";
	static final boolean DEBUG = true;
	static private long m_lastClearClosedConnection = System
			.currentTimeMillis();

	public static long CHECK_CLOSED_CONNECTION_TIME = 4 * 60 * 60 * 1000;

	static {
		initDriver();
	}

	private ConnectionPoolUtil() {

	}

	/**
	 * 初始化jdbc driver
	 */
	private static void initDriver() {
		@SuppressWarnings("unused")
		Driver driver = null;
		try {
			driver = (Driver) Class.forName("com.mysql.jdbc.Driver")
					.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 断开没有使用的连接，并与新的连接建立
	 * 
	 * @return Connection
	 */
	public static synchronized Connection getConnection() {
		clearClosedConnection();
		// 断开没有使用的连接
		while (m_notUsedConnection.size() > 0) {
			try {
				ConnectionWrapperUtil wrapper = m_notUsedConnection
						.removeFirst();
				if (wrapper.connection.isClosed()) {
					continue;
				}
				m_usedUsedConnection.add(wrapper);
				if (DEBUG) {
					wrapper.debugInfo = new Throwable(
							"Connection initial statement");
				}
				return wrapper.connection;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		int newCount = getIncreasingConnectionCount();
		LinkedList<ConnectionWrapperUtil> list = new LinkedList<ConnectionWrapperUtil>();
		ConnectionWrapperUtil wrapper = null;
		for (int i = 0; i < newCount; i++) {
			wrapper = getNewConnection();
			if (wrapper != null) {
				list.add(wrapper);
			}
		}
		if (list.size() == 0) {
			return null;
		}
		wrapper = list.removeFirst();
		m_usedUsedConnection.add(wrapper);
		m_notUsedConnection.addAll(list);
		list.clear();

		return wrapper.connection;
	}

	/**
	 * 与连接池建立新连接
	 * 
	 * @return ConnectionWrapperUtil
	 */
	private static ConnectionWrapperUtil getNewConnection() {

		try {
			Connection con = DriverManager.getConnection(m_url, m_user,
					m_password);
			ConnectionWrapperUtil wrapper = new ConnectionWrapperUtil(con);
			return wrapper;
		} catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	}

	/**
	 * 将连接池中某连接断开，添加到等待
	 * 
	 * @param con
	 *            连接池对象
	 */
	static synchronized void pushConnectionBackToPool(ConnectionWrapperUtil con) {
		boolean exist = m_usedUsedConnection.remove(con);
		if (exist) {
			m_notUsedConnection.addLast(con);
		}
	}

	/**
	 * 关闭连接
	 * 
	 * @return int
	 */
	public static int close() {
		int count = 0;
		Iterator<ConnectionWrapperUtil> iterator = m_notUsedConnection
				.iterator();
		while (iterator.hasNext()) {
			try {
				(iterator.next()).close();
				count++;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		m_notUsedConnection.clear();

		iterator = m_usedUsedConnection.iterator();
		while (iterator.hasNext()) {
			try {
				ConnectionWrapperUtil wrapper = iterator.next();
				wrapper.close();
				if (DEBUG) {
					wrapper.debugInfo.printStackTrace();
				}
				count++;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		m_usedUsedConnection.clear();
		return count;
	}

	/**
	 * 关闭并清除连接
	 */
	private static void clearClosedConnection() {
		long time = System.currentTimeMillis();
		if (time < m_lastClearClosedConnection) {
			time = m_lastClearClosedConnection;
			return;
		}

		if (time - m_lastClearClosedConnection < CHECK_CLOSED_CONNECTION_TIME) {
			return;
		}
		m_lastClearClosedConnection = time;

		Iterator<ConnectionWrapperUtil> iterator = m_notUsedConnection
				.iterator();
		while (iterator.hasNext()) {
			ConnectionWrapperUtil wrapper = iterator.next();
			try {
				if (wrapper.connection.isClosed()) {
					iterator.remove();
				}
			} catch (Exception e) {
				iterator.remove();
				if (DEBUG) {
					System.out
							.println("connection is closed,this connection is initial StackTrace ");
					wrapper.debugInfo.printStackTrace();
					e.printStackTrace();
				}
			}
		}

		int decrease = getDecreasingConnectionCount();
		if (m_notUsedConnection.size() < decrease) {
			return;
		}

		while (decrease-- > 0) {
			ConnectionWrapperUtil wrapper = m_notUsedConnection.removeFirst();
			try {
				wrapper.connection.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 获得增加的连接数
	 * 
	 * @return int
	 */
	private static int getIncreasingConnectionCount() {
		int count = 1;
		int current = getConnectionCount();
		count = current / 4;
		if (count < 1) {
			count = 1;
		}
		return count;
	}

	/**
	 * 获得减少的连接数
	 * 
	 * @return int
	 */
	public static int getDecreasingConnectionCount() {
		@SuppressWarnings("unused")
		int count = 0;
		int current = getConnectionCount();
		if (current < 10) {
			return 0;
		}

		return current / 3;
	}

	public synchronized static void printDebugMsg() {
		printDebugMsg(System.out);
	}

	/**
	 * 打印debug信息
	 * 
	 * @param out
	 */
	public synchronized static void printDebugMsg(PrintStream out) {
		if (!DEBUG) {
			return;
		}
		StringBuffer msg = new StringBuffer();
		msg.append("debug message in" + ConnectionPoolUtil.class.getName());
		msg.append("\r\n");
		msg.append("total count is connection pool:" + getConnectionCount());
		msg.append("\r\n");
		msg.append("not used connection count:" + getNotUsedConnection());
		msg.append("\r\n");
		msg.append("used connection,count:" + getUsedConnectionCount());
		out.println(msg);
		Iterator<ConnectionWrapperUtil> iterator = m_usedUsedConnection
				.iterator();
		while (iterator.hasNext()) {
			ConnectionWrapperUtil wrapper = iterator.next();
			wrapper.debugInfo.printStackTrace(out);
		}
		out.println();
	}

	public static int getConnectionCount() {
		return m_notUsedConnection.size() + m_usedUsedConnection.size();
	}

	public static int getUsedConnectionCount() {
		return m_notUsedConnection.size();
	}

	public static int getNotUsedConnection() {
		return m_usedUsedConnection.size();
	}

	public static String getUrl() {
		return m_url;
	}

	public static void setUrl(String url) {
		if (url == null) {
			return;
		}

		m_url = url.trim();
	}

	public static String getUser() {
		return m_user;
	}

	public static void setUser(String user) {
		if (user == null) {
			return;
		}
		m_user = user.trim();
	}

	public static String getPassword() {
		return m_password;
	}

	public static void setPassword(String password) {
		if (password == null) {
			return;
		}
		m_password = password.trim();
	}

	public static void main(String[] args) {
		setUrl("jdbc:mysql://"+"172.18.4.134"+":3306?zeroDateTimeBehavior=convertToNull");
		setUser("user_java");
		setPassword("java789");

		Long start = System.currentTimeMillis();
		for (int i = 0; i < 500; i++) {
			Connection con = getConnection();
			System.out.println(con.toString());
			try {
				con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		System.out.println("connectionPool:"
				+ (System.currentTimeMillis() - start));
		
	}
}